/*
 * =====================================================================================
 *
 *       Filename: util_logfilefile.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  2020年03月10日 17时52分09秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (), 
 *   Organization:  
 *
 * =====================================================================================
 */
#include "util_debug.h"
#include "util_logfile.h"
#include <time.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>

static int log_fd = -1;
static char log_file[LEN_LOGFILE_PATH + 1];
static unsigned int log_limit = 0;

static int _open_log_file()
{
    log_fd = open(log_file, O_RDWR | O_CREAT, 0666);
    if(log_fd < 0) {
        debug_err("%s: [open]: %s %s\n", __func__, log_file, strerror(errno));
        return -1;
    }
    return log_fd;
}

static void _close_log_file()
{
    if(log_fd > 0) {
        close(log_fd);
        log_fd = -1;
    }
}

static int _truncate_log_file()
{
    struct stat stat;
    if(0 != fstat(log_fd, &stat)) {
        _close_log_file();
        return -1;
    }

    if(stat.st_size > log_limit) {
        if(0 != ftruncate(log_fd, log_limit)) {
            debug_err("%s: [ftruncate]: %s\n", strerror(errno));
            _close_log_file();
            return -1;
        }
    }
    return log_fd; 
}

static int _offset_log_file()
{
    //TODO:设置文件偏移在文件最后
    if(lseek(log_fd, 0, SEEK_END) < 0) {
        debug_err("%s(): lseek(SEEK_END), %s\n", __func__, strerror(errno));
        return -1;
    }
    return 0;
}

/*
 * @file: log file path
 * @limit: log file max size(Bytes)
 */
int util_logfile_open(char *file, unsigned int limit)
{
    if(NULL == file) {
        debug_err("%s(): argument file is NULL\n");
        return -1;
    }
    if(strlen(file) > LEN_LOGFILE_PATH) {
        debug_err("%s(): logfile path is %d larger than %d,[%s]\n",
                strlen(file), LEN_LOGFILE_PATH, file);
        return -1;
    }
    
    strncpy(log_file, file, sizeof(log_file) - 1);
    if(limit <= 0) {
        log_limit = 1024 * 8;
    }
    else {
        log_limit = limit;
    }
    
    debug_print("log_file: %s, limit: %d Bytes\n", log_file, log_limit);

    if(_open_log_file() < 0) {
        return -1;
    }
    
    /* 如果日志超过log_limit:截断
     * (比如日志文件之前设置10MB,已经记录了7MB,现在设置了1MB,就需要截断了)*/
    if(_truncate_log_file() < 0) {
        _close_log_file();
        return -1;
    }

    if(_offset_log_file() < 0) {
        _close_log_file();
        return -1;
    }
    
    return log_fd;
}

void util_logfile_close()
{
    _close_log_file();
}

/*
 * limit: 是unsigned int,文件最大4个G
 */
int util_logfile(const char *fmt, ...)
{
    struct tm tm;
    struct timeval tv;
    gettimeofday(&tv, NULL);
    localtime_r(&(tv.tv_sec), &tm);

    if(log_fd < 0) {
        if(util_logfile_open("log.log", 0) < 0) {
            return -1;
        }
    }

    char timestamp[LEN_LOGFILE_TIMESTAMP] = {0};
    snprintf(timestamp, sizeof(timestamp) - 1, "%4d/%02d/%02d %02d:%02d:%02d.%06d ",
                tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)tv.tv_usec);

    char *buff = NULL;
    va_list arg;
    va_start(arg, fmt);
    int ret = vasprintf(&buff, fmt, arg);
    va_end(arg);
    if(ret > 0 && buff) {
        /* 获取当前文件的偏移 */
        int wr;
        int len = strlen(buff);
        int len_tm = strlen(timestamp);
        off_t offset = lseek(log_fd, 0, SEEK_CUR);
        if(offset + len + len_tm <= log_limit) {
            wr = write(log_fd, timestamp, len_tm);
            wr = write(log_fd, buff, len);
            wr = write(log_fd, "\n", 1);
        }
        else {
            /* 设置偏移量为0 */
            offset = lseek(log_fd, 0, SEEK_SET);
            wr = write(log_fd, timestamp, len_tm);
            wr = write(log_fd, buff, len);
            wr = write(log_fd, "\n", 1);
        }
        free(buff);
    }
    fsync(log_fd);
    return ret;
}

